/**
 * 网页应用经常想要在非时间临界操作的事件循环帧中执行一些计算任务，但往往需要大量时间。
 * 这些任务就是后台任务，典型的后台任务比如：记录分析数据、长时运行数据处理、客户端模板化以及未来的预渲染。
 * 这些任务必须和事件处理或者基于脚本的动画等时间临界操作分享事件循环。
 * 后台任务通常是通过分配 setTimeout 回调，在回调中执行。
 * 
 * 缺点在于用户代理（浏览器）无法区分这一次的回调是时间临界操作还是可以推迟到空闲时执行。
 * 此外，浏览器也无法提供有关不延迟时间临界操作的情况下，可以继续执行多长时间，以及导致闪避和其他用户可察觉的延迟的任何信息。
 * 作为结果，最简单的实现方式时通过极小的延迟调用 setTimeout ，并在回调中执行尽可能小的功能块，再进其他工作交给另外的 setTimeout
 * 
 * 从上面的介绍不难看出，background task 在使用场景是与 Web Worker 相似，我觉得应该可以用 Web Worker 实现这一切。
 * 不同在于 background tast 执行是交给 主线程 的，挂载在 event loop 队列上，Web Worker 则是独立的子进程
 * 
 * 更大的问题在于兼容性，Edge 没有兼容本规范，因此...几乎是不可用的。
 */

// 兼容处理
window.requestIdleCallback = window.requestIdleCallback || function (handler) {
  let startTime = Date.now();
  return setTimeout(function () {
    handler({
      didTimeout: false,
      timeRemaining: function () {
        return Math.max(0, 50.0 - (Date.now() - startTime));
      }
    })
  }, 1);
}

let requestId = 0, pointsTotal = 0, pointsInside = 0;

// 插入空闲循环的耗时计算
function piStep () {
  let r = 10, x = y = Math.random() * r * 2 - r;
  return (Math.pow(x, 2) + Math.pow(y, 2) < Math.pow(r, 2));
}

/**
 * 后台任务的回调函数，内部逻辑显示每次耗时任务的时长
 * @param {DOMHighResTimeStamp} deadline 
 */
function refinePi (deadline) {
  while (deadline.timeRemaining() > 0) {
    if(piStep()) {
      pointsInside++;
    }
    pointsTotal++;
  }
  let curEstimate = (4 * pointsInside / pointsTotal);
  let textElement = document.getElementById('piEstimate');
  textElement.innerHTML = `Pi Estimate ${curEstimate}`;
  requestId = window.requestIdleCallback(refinePi);
}

// 开始按钮点击处理
function start() {
  requestId = window.requestIdleCallback(refinePi);
}
// 停止按钮点击处理
function stop () {
  if(requestId) {
    window.cancelIdleCallback(requestId);
  }
  requestId = 0;
}